#include "wc3collections.h"
#include "Extern_global_Variable.h"

template <typename T, typename TInitialOffset>
TSLinkedList<T, TInitialOffset>::TLinkedListReversedEnumerator::TLinkedListReversedEnumerator(PSLinkedList AList)
{
	FList = AList;
	Reset();
}

template <typename T, typename TInitialOffset>
typename TSLinkedList<T,TInitialOffset>::P TSLinkedList<T, TInitialOffset>::TLinkedListReversedEnumerator::GetCurrent()
{
	return FCurrent;
}

template <typename T, typename TInitialOffset>
Boolean TSLinkedList<T, TInitialOffset>::TLinkedListReversedEnumerator::MoveNext()
{
	Boolean Result;
	Result = FALSE;
	FCurrent = (*FCurrentNode).Value;
	Result = FCurrent > 0;

	if (Result == TRUE)
	{
		FCurrentNode = (*FCurrentNode).Previous;
	}
	return Result;
}

template <typename T, typename TInitialOffset>
procedure TSLinkedList<T, TInitialOffset>::TLinkedListReversedEnumerator::Reset()
{
	FCurrent = NULL;
	FCurrentNode = (*(*FList).FRoot.Previous);
}

procedure TMissingArrayItemManager::Initialize(Pointer AItem, SizeUInt Size)
{
	MessageBoxA(NULL,"missing array item manager","Error!",MB_OK | MB_ICONWARNING);
}

procedure TMissingArrayItemManager::Finalize(Pointer AItem, SizeUInt Size)
{
	MessageBoxA(NULL,"missing array item manager","Error!",MB_OK | MB_ICONWARNING);
}

procedure TMissingArrayItemManager::Copy(Pointer ADestination, const Pointer ASource,
	SizeUInt Size)
{
	MessageBoxA(NULL,"missing array item manager","Error!",MB_OK | MB_ICONWARNING);
}

Dword THashlessKeyManager::GetKeyHash(const Pointer AKey)
{
	return *((Dword *)AKey);
}

Boolean THashlessKeyManager::IsKeysEqual(const Pointer KeyA, const Pointer KeyB)
{
	return TRUE;
}

procedure THashlessKeyManager::CopyKey(Pointer Destination, const Pointer Source)
{

}

procedure THashlessKeyManager::ClearKey(Pointer AKey)
{

}

Boolean GPTrue::GetValue()
{
	return TRUE;
}

Boolean GPFalse::GetValue()
{
	return FALSE;
}

//{ TConstantStringHashKeyManager }
//
//function TConstantStringHashKeyManager.GetKeyHash(const AKey: PChar): Dword;
//begin
//	Result = SStrHash32(AKey);
//end;
//
//function TConstantStringHashKeyManager.IsKeysEqual(const KeyA, KeyB: PChar
//	): Boolean;
//begin
//	Result = (KeyA = KeyB) or (StrComp(KeyA, KeyB) = 0);
//end;
//
//procedure TConstantStringHashKeyManager.CopyKey(out Destination: PChar;
//	const Source: PChar);
//begin
//	Destination = Source;
//end;
//
//procedure TConstantStringHashKeyManager.ClearKey(var AKey: PChar);
//begin
//	AKey = NULL;
//end;

template <typename TCloneKey, typename TCaseSensetive>
Dword TStringHashKeyManagerBase<TCloneKey,TCaseSensetive>::GetKeyHash(const PChar AKey)
{
	return SStrHash32(AKey);
}

template <typename TCloneKey, typename TCaseSensetive>
Boolean TStringHashKeyManagerBase<TCloneKey,TCaseSensetive>::IsKeysEqual(const PChar KeyA, const PChar KeyB)
{
	int vLenA, vLenB;
	vLenA = strlen(KeyA);
	vLenB = strlen(KeyB);
	if ((!TCloneKey::GetValue()) && vLenA == vLenB && (memcmp(KeyA,KeyB,vLenA) == 0))
	{
		return TRUE;
	}

	if (TCaseSensetive::GetValue() && vLenA == vLenB)
	{
		return (memcmp(KeyA,KeyB,vLenA) == 0);
	}
	else
	{
		return (memicmp(KeyA,KeyB,vLenA) == 0);
	}
	return FALSE;
}

template <typename TCloneKey, typename TCaseSensetive>
procedure TStringHashKeyManagerBase<TCloneKey,TCaseSensetive>::CopyKey(PChar &Destination, const PChar Source)
{
	if (TCloneKey::GetValue())
	{
		Destination = CloneString(Source);
	}
	else
	{
		Destination = Source;
	}
}

template <typename TCloneKey, typename TCaseSensetive>
procedure TStringHashKeyManagerBase<TCloneKey,TCaseSensetive>::ClearKey(PChar &AKey)
{
	if (TCloneKey.GetValue())
	{
		wc3memory.Free(AKey);
	}
	AKey = NULL;
}

Pointer TSHashTable_VMT::CreateItem(Pointer this_1, Pointer List,
	SizeUInt ExtraSize, Dword ExtraFlags)
{
	__asm
	{
		mov ecx, this_1
	}
	return pCreateItem(List, ExtraSize, ExtraFlags);
}

procedure TSHashTable_VMT::DeleteItem(Pointer this_1,Pointer Item)
{
	__asm
	{
		mov ecx, this_1
	}
	pDeleteItem(Item);
}

template <typename TKey, typename TValue, typename TKeyManager>
SizeUInt TSHashTable<TKey,TValue,TKeyManager>::TItemsNodeOffset::GetValue()
{
	*PValue = NULL;
	return (SizeUInt)(PValue->HashKeyData.ItemsNode);
}

template <typename TKey, typename TValue, typename TKeyManager>
SizeUInt TSHashTable<TKey,TValue,TKeyManager>::TPageNodeOffset::GetValue()
{
	*PValue = NULL;
	return (SizeUInt)(PValue->HashKeyData.PageNode);
}

template<typename P>
Boolean TSLinkedNode<P>::IsLinked()
{
	return Previous != NULL;
}

template<typename P>
procedure TSLinkedNode<P>::Clear()
{
	Previous = NULL;
	Value = NULL;
}

template<typename P>
procedure TSLinkedNode<P>::Lock()
{
	Previous = this;
	Value = P(!((UInt)(this)));
}

template<typename TPage, typename TPageManager>
TSGrowableArrayM<TPage, TPageManager>::TSGrowableArrayM()
{
	//inherited;
	FGrowFactor = 0;
}

template<typename TPage, typename TPageManager>
TSGrowableArrayM<TPage, TPageManager>::~TSGrowableArrayM()
{

}

template<typename T>
TSGrowableArray<T>::TSGrowableArray()
{

}

template<typename T>
TSGrowableArray<T>::~TSGrowableArray()
{

}


SizeUInt TMissingInitialOffset::GetValue()
{
	MessageBoxA(NULL,"Attempt to init incorrect linked list.","Error!",MB_OK | MB_ICONWARNING);
	return NULL;
}

template<typename TItem>
procedure TArrayOfObjectsManager<TItem>::Initialize(TItem *AItem, SizeUInt Size)
{
	(*AItem).TSLinkedList::TSLinkedList();
}

template<typename TItem>
procedure TArrayOfObjectsManager<TItem>::Finalize(TItem *AItem, SizeUInt Size)
{
	(*AItem).TSLinkedList::~TSLinkedList();
}

template<typename TItem>
procedure TArrayOfObjectsManager<TItem>::Copy(TItem *ADestination,
	const TItem ASource, SizeUInt Size)
{
	ADestination = ASource;
}

template<typename T, typename TItemManager>
typename TSArrayM<T,TItemManager>::P TSArrayM<T,TItemManager>::TArrayItemPointers::GetItem(Dword AIndex)
{
	return &FOwner->FItems[AIndex];
}

template<typename T, typename TItemManager>
TSArrayM<T,TItemManager>::TArrayItemPointers::TArrayItemPointers(PSArray AOwner)
{
	FOwner = AOwner;
}

template<typename T, typename TItemManager>
typename TSArrayM<T,TItemManager>::TArrayItemPointers::TArrayItemPointersEnumerator TSArrayM<T,TItemManager>::TArrayItemPointers::GetEnumerator()
{
	TArrayItemPointersEnumerator<T,TItemManager> Result;
	Result.TArrayItemPointersEnumerator(FOwner);
	return Result;
}

template<typename T, typename TItemManager>
TSArrayM<T,TItemManager>::TArrayItemPointers::TArrayItemPointersEnumerator::TArrayItemPointersEnumerator(
	PSArray AOwner)
{
	FOwner = AOwner;
	Reset();
}

template<typename T, typename TItemManager>
typename TSArrayM<T,TItemManager>::P TSArrayM<T,TItemManager>::TArrayItemPointers::TArrayItemPointersEnumerator::GetCurrent()
{
	return FOwner->FItems[FCurrentIndex];
}

template<typename T, typename TItemManager>
Boolean TSArrayM<T,TItemManager>::TArrayItemPointers::TArrayItemPointersEnumerator::MoveNext()
{
	FCurrentIndex++;
	return FCurrentIndex < (*FOwner).Length;
}

template<typename T, typename TItemManager>
procedure TSArrayM<T,TItemManager>::TArrayItemPointers::TArrayItemPointersEnumerator::Reset()
{
	FCurrentIndex = (Dword)(-1);
}

procedure TDefaultArrayItemManager::Initialize(Pointer AItem, SizeUInt Size)
{

}

procedure TDefaultArrayItemManager::Finalize(Pointer AItem, SizeUInt Size)
{

}

procedure TDefaultArrayItemManager::Copy(Pointer ADestination, const Pointer ASource, SizeUInt Size)
{
	memcpy(ASource, ADestination, Size);
}

template<typename T, typename TItemManager>
Dword TSArrayM<T,TItemManager>::GetLength()
{
	return FLength;
}

template<typename T, typename TItemManager>
Dword TSArrayM<T,TItemManager>::GetCapacity()
{
	return FCapacity;
}

template<typename T, typename TItemManager>
procedure TSArrayM<T,TItemManager>::SetLength(Dword ALength)
{
	Dword vvi;
	Dword First;
	Dword Last;

	if (ALength < FLength)
	{
		First = ALength;
		Last = FLength - 1;
		for (vvi = First; vvi <= Last; vvi++)
		{
			TItemManager::Finalize(&FItems[vvi], sizeof(T));
		}
	}

	if (ALength > FCapacity)
	{
		FCapacity = ALength;
	}

	if (ALength > FLength)
	{
		First = FLength;
		Last = ALength - 1;
		for (vvi = First; vvi <= Last; vvi++)
		{
			TItemManager::Initialize(&FItems[vvi], sizeof(T));
		}
	}

	FLength = ALength;
}

template<typename T, typename TItemManager>
procedure TSArrayM<T,TItemManager>::SetCapacity(Dword ACapacity)
{
	SizeUInt BufferSize;

    if (ACapacity != FCapacity)
	{
		if (ACapacity < Length)
		{
			Length = ACapacity;
		}

		BufferSize = ACapacity * (SizeUInt*)(SizeOf(T));

		if (FItems == NULL)
		{
			FItems = Allocate(BufferSize)
		}
		else
		{
			FItems = ReAllocate(FItems, BufferSize);
		}

		FCapacity = ACapacity;
	}
}

template<typename T, typename TItemManager>
T TSArrayM<T,TItemManager>::GetItem(Dword AIndex)
{
	if (AIndex < FLength)
	{
		return FItems[AIndex];
	}
	else
	{
		char vStrError[50];
		sprintf(vStrError,"index %d out of range",AIndex);
		MessageBoxA(NULL,vStrError,"Error!",MB_OK | MB_ICONWARNING);
	}
	T vT;
	return vT;
}

template<typename T, typename TItemManager>
procedure TSArrayM<T,TItemManager>::SetItem(Dword AIndex, const T AValue)
{
	TItemManager::Copy((Pointer)FItems[AIndex], (Pointer)AValue, sizeof(T));
}

template<typename T, typename TItemManager>
typename TSArrayM<T,TItemManager>::TArrayItemPointers TSArrayM<T,TItemManager>::GetItemPointers()
{
	return *vTArrayItemPointers;
}

template<typename T, typename TItemManager>
TSArrayM<T,TItemManager>::TSArrayM()
{
	vTArrayItemPointers = new TArrayItemPointers(this);
	FCapacity = 0;
	FLength = 0;
	FItems = NULL;
}

template<typename T, typename TItemManager>
TSArrayM<T,TItemManager>::~TSArrayM()
{
	FCapacity = 0;
}

template<typename T, typename TItemManager>
Dword TSArrayM<T,TItemManager>::Add(T AValue)
{
	Dword Result;
	Result = FLength;
	FLength = FLength + 1;
	FItems[Result] = AValue;
	return Result;
}

template<typename T, typename TItemManager>
typename TSArrayM<T,TItemManager>::P TSArrayM<T,TItemManager>::GetNewItem()
{
	P Result;
	FLength = FLength + 1;
	Result = GetItemPointers().GetItem(FLength-1);
	return Result;
}

template<typename T, typename TItemManager>
T TSArrayM<T,TItemManager>::Pop()
{
	T Result;
	if (FLength == 0)
	{
		MessageBoxA(NULL,"list is empty","Error!",MB_OK | MB_ICONWARNING);
	}

	Result = GetItem(FLength-1);
	FLength = FLength - 1;
	return Result;
}

template<typename T, typename TItemManager>
typename TSArrayM<T,TItemManager>::TArrayEnumerator TSArrayM<T,TItemManager>::GetEnumerator()
{
	return TArrayEnumerator(&this);
}

template<typename T, typename TItemManager>
TSArrayM<T,TItemManager>::TArrayEnumerator::TArrayEnumerator(PSArray AArray)
{
	FArray = AArray;
	Reset();
}

template<typename T, typename TItemManager>
T TSArrayM<T,TItemManager>::TArrayEnumerator::GetCurrent()
{
	return (*FArray).FItems[FCurrent];
}

template<typename T, typename TItemManager>
Boolean TSArrayM<T,TItemManager>::TArrayEnumerator::MoveNext()
{
	FCurrent++;
	return FCurrent < (*FArray).Length;
}

template<typename T, typename TItemManager>
procedure TSArrayM<T,TItemManager>::TArrayEnumerator::Reset()
{
	FCurrent = (Dword)(-1);
}

template<typename T, typename TInitialOffset>
Integer TSLinkedList<T,TInitialOffset>::GetLength()
{
	Integer Result;

	//Result = 1;//sizeof(*this)/sizeof(this[0]);
	P Item;
	P Last;
	Last = GetLast();

	Result = 0;
	Item = NULL;
	while (Item != Last)
	{
		if (Item == NULL)
		{
			Item = GetFirst();
		}
		else
		{
			Item = GetNextItem(Item);
		}
		Result++;
	}
	return Result;
}

template<typename T, typename TInitialOffset>
typename TSLinkedList<T,TInitialOffset>::PNode TSLinkedList<T,TInitialOffset>::GetNodeOfItem(P AItem)
{
	return (PNode)((Dword)(AItem) + FOffset);
}

template<typename T, typename TInitialOffset>
typename TSLinkedList<T,TInitialOffset>::P TSLinkedList<T,TInitialOffset>::GetItemOfNode(PNode ANode)
{
	return (P)((DWord)(ANode) - FOffset);
}

template<typename T, typename TInitialOffset>
typename TSLinkedList<T,TInitialOffset>::PNode TSLinkedList<T,TInitialOffset>::GetNextNode(PNode ANode)
{
	PNode Result;
	if (&((*ANode).Value) > 0)
	{
		Result = GetNodeOfItem((*ANode).Value);
	}
	else
	{
		Result = (PNode)(!((PtrUInt)((*ANode).Value)));
	}
	return Result;
}

template<typename T, typename TInitialOffset>
procedure TSLinkedList<T,TInitialOffset>::UnlinkNode(PNode ANode)
{
	if ((*ANode).IsLinked())
	{
		(*(*ANode).Previous).Value = (*ANode).Value;
		(*GetNextNode(ANode)).Previous = (*ANode).Previous;
	}
	(*ANode).Clear();
}

template<typename T, typename TInitialOffset>
procedure TSLinkedList<T,TInitialOffset>::InsertValueAfter(PNode ANode,P AValue)
{
	PNode NewNode;

	NewNode = GetNodeOfItem(AValue);
	(*NewNode).Previous = ANode;
	(*NewNode).Value = (*ANode).Value;

	(*ANode).Value = AValue;
	(*GetNextNode(NewNode)).Previous = NewNode;
}

template<typename T, typename TInitialOffset>
procedure TSLinkedList<T,TInitialOffset>::LinkNodes(PNode ANodeA, PNode ANodeB)
{
	(*ANodeA).Previous = ANodeB;
	(*ANodeB).Value = GetItemOfNode(ANodeA);
}

template<typename T, typename TInitialOffset>
typename TSLinkedList<T,TInitialOffset>::P TSLinkedList<T,TInitialOffset>::GetFirst()
{
	P Result;
	Result = FRoot.Value;
	if ((&Result) <= 0)
	{
		Result = NULL;
	}
	return Result;
}

template<typename T, typename TInitialOffset>
typename TSLinkedList<T,TInitialOffset>::P TSLinkedList<T,TInitialOffset>::GetLast()
{
	P Result;
	Result = (*(*FRoot.Previous).Previous).Value;
	if ((&Result) <= 0)
	{
		Result = NULL;
	}
	return Result;
}

template<typename T, typename TInitialOffset>
TSLinkedList<T,TInitialOffset>::TSLinkedList()
{
	TInitialOffset vTInitialOffset;
	//FOffset = vTInitialOffset.GetValue();
	FRoot.Lock();
}

template<typename T, typename TInitialOffset>
TSLinkedList<T,TInitialOffset>::~TSLinkedList()
{
	Clear();
}

template<typename T, typename TInitialOffset>
procedure TSLinkedList<T,TInitialOffset>::Add(P AItem)
{
	UnlinkNode(GetNodeOfItem(AItem));
	InsertValueAfter(FRoot.Previous, AItem);
}

template<typename T, typename TInitialOffset>
procedure TSLinkedList<T,TInitialOffset>::Prepend(P AItem)
{
	UnlinkNode(GetNodeOfItem(AItem));
	InsertValueAfter(&FRoot, AItem);
}

template<typename T, typename TInitialOffset>
procedure TSLinkedList<T,TInitialOffset>::Remove(P AItem)
{
	UnlinkNode(GetNodeOfItem(AItem));
}

template<typename T, typename TInitialOffset>
procedure TSLinkedList<T,TInitialOffset>::Clear()
{
	PNode Current, Next;

	Current = FRoot.Previous;
	while (Current != &FRoot)
	{
		Next = (*Current).Previous;
		(*Current).Clear();
		Current = Next;
	}
	FRoot.Lock();
}

template<typename T, typename TInitialOffset>
typename TSLinkedList<T,TInitialOffset>::P TSLinkedList<T,TInitialOffset>::GetNextItem(P AItem)
{
	P Result;
	Result = (*GetNodeOfItem(AItem)).Value;
	if ((&Result) <= 0)
	{
		Result = NULL;
	}
	return Result;
}

template<typename T, typename TInitialOffset>
TLinkedListEnumerator_2<T,TInitialOffset> TSLinkedList<T,TInitialOffset>::GetEnumerator()
{
	return TLinkedListEnumerator(&this);
}

template<typename T, typename TInitialOffset>
TLinkedListReversedEnumerator_2<T,TInitialOffset> TSLinkedList<T,TInitialOffset>::GetReversedEnumerator()
{
	return TLinkedListReversedEnumerator(&this);
}

template<typename T, typename TInitialOffset>
TSLinkedList<T,TInitialOffset>::TLinkedListEnumerator::TLinkedListEnumerator(PSLinkedList AList)
{
	FList = AList;
	Reset();
}

template<typename T, typename TInitialOffset>
TLinkedListEnumerator_2<T,TInitialOffset> TSLinkedList<T,TInitialOffset>::TLinkedListEnumerator::GetEnumerator()
{
	return this;
}

template<typename T, typename TInitialOffset>
typename TSLinkedList<T,TInitialOffset>::P TSLinkedList<T,TInitialOffset>::TLinkedListEnumerator::GetCurrent()
{
	return FCurrent;
}

template<typename T, typename TInitialOffset>
Boolean TSLinkedList<T,TInitialOffset>::TLinkedListEnumerator::MoveNext()
{
	Boolean Result;
	FCurrent = (*FCurrentNode).Value;
	Result = (&FCurrent) > 0;

	if (Result)
	{
		FCurrentNode = (*FList).GetNodeOfItem(FCurrent);
	}
	return Result;
}

template<typename T, typename TInitialOffset>
procedure TSLinkedList<T,TInitialOffset>::TLinkedListEnumerator::Reset()
{
	FCurrent = NULL;
	FCurrentNode = (*FList).FRoot;
}

template <typename TKey, typename TValue, typename TKeyManager>
procedure TSHashTable<TKey,TValue,TKeyManager>::InitPages()
{
	Pages.SetLength(INITIAL_PAGES_COUNT);
	HashMask = Pages.GetLength() - 1;
}

template <typename TKey, typename TValue, typename TKeyManager>
procedure TSHashTable<TKey,TValue,TKeyManager>::Grow()
{
	if (Pages.GetLength() < MAX_PAGES_COUNT)
	{
		SetPagesCount(Pages.GetLength() * 2);
	}
}

template <typename TKey, typename TValue, typename TKeyManager>
procedure TSHashTable<TKey,TValue,TKeyManager>::SetPagesCount(Dword ACount)
{
	Integer vvi;
	PPage Page;
	PValue Item;
	Dword Index;

	// Copying linked list causes nodes to point to wrong memory locations.
	// Destroy and recreate from scratch.
	Pages.SetLength(0);
	Pages.SetLength(ACount);
	HashMask = Pages.GetLength() - 1;

	for (vvi = 0; vvi <= Items.GetLength() - 1; vvi++)
	{
		if (vvi == 0)
		{
			Item = Items.GetFirst();
		}
		else
		{
			Item = Items.GetNextItem(Item);
		}
		Index = (*Item).HashKeyData.Hash && HashMask;
		Page = Pages.GetItemPointers().GetItem(Index);
		(*Page).Add(Item);
	}
}

template <typename TKey, typename TValue, typename TKeyManager>
Boolean TSHashTable<TKey,TValue,TKeyManager>::Find(const TKey AKey, Dword AHash, PValue &AValue)
{
	Integer vvi;
	Boolean Result;
	Integer Index;
	PValue Item;

	AValue = NULL;
	Result = FALSE;

	if (HashMask == (Dword)(-1)) return Result;
	Index = AHash && HashMask;

	for (vvi = 0; vvi <= Pages.GetLength(); vvi++)
	{
		if (vvi == 0)
		{
			Item = Pages.GetItem(Index).GetFirst();
		}
		else
		{
			Item = Pages.GetItem(Index).GetNextItem(Item);
		}
		if (((*Item).HashKeyData.Hash == AHash) &&
			TKeyManager::IsKeysEqual((*Item).HashKeyData.Key, AKey))
		{
			AValue = Item;
			Result = TRUE;
			break;
		}
	}
	return Result;
}

template <typename TKey, typename TValue, typename TKeyManager>
TValue* TSHashTable<TKey,TValue,TKeyManager>::Get(const TKey AKey, Dword AHash)
{
	if (!Find(AKey, AHash, Result))
	{
		MessageBoxA(NULL,"key error","Error!",MB_OK | MB_ICONWARNING);
	}
}

template <typename TKey, typename TValue, typename TKeyManager>
Boolean TSHashTable<TKey,TValue,TKeyManager>::Find(const TKey AKey, PValue &AValue)
{
	Boolean Result;
	Dword Hash;

	Hash = TKeyManager::GetKeyHash(AKey);
	Result = Find(AKey, Hash, AValue);
	return Result;
}

template <typename TKey, typename TValue, typename TKeyManager>
TValue* TSHashTable<TKey,TValue,TKeyManager>::Get(const TKey AKey)
{
	Dword Hash;

	Hash = TKeyManager.GetKeyHash(AKey);
	return Get(AKey, Hash);
}

template <typename TKey, typename TValue, typename TKeyManager>
procedure TSHashTable<TKey,TValue,TKeyManager>::Put(PValue AValue)
{
	Dword Index;

	Items.Add(AValue);

	if (HashMask =- (Dword)(-1))
	{
		InitPages();
	}

	Index = (*AValue).HashKeyData.Hash && HashMask;
	(*Pages.GetItemPointers().GetItem(Index)).Add(AValue);

	if ((*Pages.GetItemPointers().GetItem(Index)).GetLength() > PAGE_LIMIT)
	{
		Grow();
	}
}

template <typename TKey, typename TValue, typename TKeyManager>
procedure TSHashTable<TKey,TValue,TKeyManager>::Put(const TKey AKey, PValue AValue)
{
	(*AValue).HashKeyData.Hash = TKeyManager::GetKeyHash(AKey);
	TKeyManager::CopyKey((*AValue).HashKeyData.Key, AKey);
	Put(AValue);
}

template <typename TKey, typename TValue, typename TKeyManager>
procedure TSHashTable<TKey,TValue,TKeyManager>::FastPut(const TKey AKey, Dword AHash, PValue AValue)
{
	Dword Index;

	((TSHashObject<TKey>*)AValue)->HashKeyData.Hash = AHash; // TKeyManager.GetKeyHash(AKey);
	TKeyManager::CopyKey(((TSHashObject<TKey>*)AValue)->HashKeyData.Key, AKey);

	Items.Add(AValue);

	if (HashMask == (Dword)(-1))
	{
		InitPages();
	}

	Index = ((TSHashObject<TKey>*)AValue)->HashKeyData.Hash && HashMask;
	Pages.GetItemPointers().GetItem(Index)->Add(AValue);

	//if Pages[Index].Length > PAGE_LIMIT then
	//	Grow;
}

template <typename TKey, typename TValue, typename TKeyManager>
Boolean TSHashTable<TKey,TValue,TKeyManager>::Remove(const TKey AKey)
{
	Integer vvi;
	Boolean Result;
	Dword Hash;
	Integer Index;
	PPage Page;
	PValue Item;

	Result = FALSE;

	Hash = TKeyManager::GetKeyHash(AKey);
	Index = Hash && HashMask;

	if (Index > Pages.GetLength()-1)
	{
		return Result;
	}

	Page = Pages.GetItemPointers().GetItem(Index);

	for (vvi = 0; vvi <= Page->GetLength(); vvi++)
	{
		if (vvi == 0)
		{
			Item = Page->GetFirst();
		}
		else
		{
			Item = Page->GetNextItem(Item);
		}
		if (((*Item).HashKeyData.Hash == Hash) &&
			TKeyManager::IsKeysEqual((*Item).HashKeyData.Key, AKey))
		{
			Items.Remove(Item);
			(*Page).Remove(Item);
			(*PSHashTable_VMT(vtable)).DeleteItem((Pointer)this, Item);

			Result = TRUE;
			break;
		}
	}
	return Result;
}

template <typename TKey, typename TValue, typename TKeyManager>
procedure TSHashTable<TKey,TValue,TKeyManager>::Clear()
{
	Integer vvi;
	PPage Page;

	Items.Clear();

	for (vvi = 0; vvi <= sizeof(*Pages.GetItemPointers().FOwner)/sizeof(Pages.GetItemPointers().FOwner[0]); vvi++)
	{
		Page = Pages.GetItemPointers().GetItem(vvi);
		(*Page).Clear();
	}
}

template <typename TKey, typename TValue, typename TKeyManager>
typename TSHashTable<TKey,TValue,TKeyManager>::PValue TSHashTable<TKey,TValue,TKeyManager>::CreateItem(const TKey AKey)
{
	PValue Result;
	//TSHashNode<TKey,TValue> vTSHashNode;
	//vTSHashNode.Value = this;
	Pointer v1, v2;
	v1 = (Pointer)this;
	v2 = (Pointer)&Items;
	//Result = (*((PSHashTable_VMT)(vtable))).CreateItem((Pointer)this, (Pointer)&Items, 0, 0);
	Put(AKey, Result);
	return Result;
}

template <typename TKey, typename TValue, typename TKeyManager>
TItems_TLinkedListReversedEnumerator<TKey,TValue,TKeyManager> TSHashTable<TKey,TValue,TKeyManager>::GetEnumerator()
{
	return TItems_TLinkedListReversedEnumerator<TKey,TValue,TKeyManager>::GetReversedEnumerator();
}

template <typename TKey, typename TValue, typename TKeyManager>
TSHashTable<TKey,TValue,TKeyManager>::TSHashTable()
{
	vtable = NULL;
	Items.TSLinkedList::TSLinkedList();
	Counter = 0;
	Pages.TSGrowableArrayM::TSGrowableArrayM();
	HashMask = (Dword)(-1);
}

template <typename TKey, typename TValue, typename TKeyManager>
TSHashTable<TKey,TValue,TKeyManager>::~TSHashTable()
{
	Items.~TSLinkedList();
	Pages.~TSGrowableArrayM();
}
